对于中文,nltk能做哪些事情
NLTK学习-1
英文分词与词性标注
#分词
word_list = nltk.word_tokenize(text)
#标注
nltk.pos_tag(word_list)
我们最熟悉的nltk大概就是上面这样,而且因为适用场景主要是外文数据。所以没怎么碰nltk,这阵子又重新翻看了《用python做自然语言处理》一书(一年前看的时候因为不能处理中文,就没怎么学),发现稍微处理下中文数据,也是可以用强大的nltk实现的。下面我们开始尝试用nltk对中文数据进行分析,看看能做哪些东西。
一、搜索词语
这一章节,可以让你了解词语上下文查找、相似词语查找、统计词频、制作离散图。
实现上面的功能需要先将文本处理成nltk容易处理的Text类,方便进行文本搜索及计算。
1.1以三体小说为例,初始化Text类
from nltk.text import Text
novel_data = open('texts/三体全集.txt').read()
#清除无关信息,只保留中文文本
cleaned_data = ''.join(re.findall(r'[\u4e00-\u9fa5]', novel_data))
wordlist = jieba.lcut(cleaned_data)
#初始化三体分词后的词语列表数据为Text类
text = Text(wordlist)
1.2word的上下文
词语word在text中的上下文
#三体 的上下文,打印宽度20字符,共10行的上下文
text.concordance(word='三体',width=20,lines=10)
Displaying 10 of 841 matches:
荐 好书 刘慈欣 三体 三体 终于 能
书 刘慈欣 三体 三体 终于 能 与 科
天立地 的 大字 三体 随后 出现 丁
再次 开始 在 三体 世界 中 命运
但 汪淼 明白 三体 的 真实 不 在
至 两个 数量级 三体 正是 这样 它
他 突然 悟出 三体 的 不 寻常 在
绳任 其 回到 三体 世界 飞星 关键
栗 他 想起 了 三体 中 的 那些 巨
它 最好 游戏 三体 难道 它 与 这
1.3word的上下文中最相似的10个词
#word =文明#在word上下文中找到最相思的10个词
text.similar(word='文明',num=10)
世界 人 他 太阳 宇宙 人类 时代 我们 舰队 方向
1.4多个词的上下文
Text.common_contexts([word1, word2])
在_中 进入_时 到_的 是_的 的_世界 看到_的 和_的 和_两个
1.5 统计词语频数
text.count(word='三体')
841
1.6离散图
"""
画出三体人物出现位置,横坐标为每个词出现在text中的索引位置
从图中基本上可以看出每个人物的出现在小说中的顺序。
汪淼和叶文洁出现在《三体》开头
罗辑几乎贯穿《三体》
维德、程心、云天明出现在《三体》末尾
"""
words=['汪淼','叶文洁','章北海','申玉菲','罗辑','史强','庄颜','维德','程心','艾AA','云天明']
text.dispersion_plot(words)
1.7 按照已有风格,随机生成文本
根据text文本风格,按照给定的words随机生成一串文本。
但是不知道为啥,这里我没运行出来。 网上查了下,说可能跟nltk版本有关,待考证。
words = ['技术','三体']
print(text.generate(words))
没有运行出来,待解决
None
二、计算词语相似度
计算某个词与其他所有词的相似度这个功能,首先要将数据初始化为ContextIndex类。
from nltk.text import ContextIndex
#初始化三体分词后的词语列表数据为ContentIndex类
contentindex = ContextIndex(wordlist)
#计算各个词与word的相似度值,返回字典
similarity_scores = contentindex.word_similarity_dict(word='三体')
#保留关联度大于0.02的词语#为了减少打印的词语的数量,我这里选择的阈值为0.02
for key,value in similarity_scores.items():
if value>0.02:
print(key,value)
三体 1.0
那个 0.025295109612141653
其他 0.0224159402241594
这个 0.029950083194675542
地球 0.06006006006006005
中国 0.02147239263803681
两个 0.03639846743295019
宇宙 0.024855012427506214
所有 0.026286966046002194
整个 0.020618556701030927
每个 0.025974025974025976
人类 0.03790087463556851
太阳系 0.023379383634431455
太空 0.029654036243822072
外星 0.0374414976599064
三维 0.03193033381712627
亚洲 0.028846153846153848
掩体 0.023809523809523808
三、计算TF-IDF
TF-IDF值反映了一个词代表某类文本的代表性的程度。比如金融类文本中,“股票”具有很强的代表性,相反“美食”几乎不具有代表性。
tf-idf值越大,说明这个词对于这类文本越具有代表性。
3.1 tf-idf学习
TF-IDF,最开始用于信息检索,在信息检索中其计算过程如下
TF-IDF模型的主要思想是:如果词w在一篇文档d中出现的频率高,并且在其他文档中很少出现,则认为词w具有很好的区分能力,适合用来把文章d和其他文章区分开来。该模型主要包含了两个因素:TF,IDF
词频TF(Term Frequency):词w在文档d中出现次数count(w, d)和文档d中总词数size(d)的比值:
逆向文档频率IDF(Inverse Document Frequency):文档总数n与词w所出现文件数docs(w, D)比值的对数:
TF-IDF= TF * IDF =(词频*词权)
TF-IDF与一个词在文档中的出现次数成正比,与该词在整个语言中的出现次数成反比。所以,自动提取关键词的算法就很清楚了,就是计算出文档的每个词的TF-IDF值,然后按降序排列,取排在最前面的几个词。
3.2 实战
先将数据初始化为TextCollection类
#TF-IDF
from nltk.text import TextCollection
import re
import jieba
def text(file):
"""
该函数用来读取文件中的中文数据
"""
novel_data = open(file).read()
cleaned_data = ''.join(re.findall(r'[\u4e00-\u9fa5]', novel_data))
wordlist = jieba.lcut(cleaned_data)
return cleaned_data
#不同种类的文本
text1 = text(file='texts/体育.txt')
text2 = text(file='texts/财经.txt')
text3 = text(file='texts/新闻.txt')
text4 = text(file='texts/科技.txt')
#将文本列表初始化为TextCollection类
mytexts = TextCollection([text1,text2,text3,text4])
3.2.1 计算tf
mytexts.idf('金融')
0.6931471805599453
3.2.2 计算idf
#计算 金融 在 各个text的tf值
print(mytexts.tf('金融',text1))
print(mytexts.tf('金融',text2))
print(mytexts.tf('金融',text3))
print(mytexts.tf('金融',text4))
0.0
0.015074986401429792
0.0
0.0008085008085008085
3.2.3 计算tf-idf
#计算 金融在 各个text中的tf-idf值
print(mytexts.tf_idf('金融', text1))
print(mytexts.tf_idf('金融', text2))
print(mytexts.tf_idf('金融', text3))
print(mytexts.tf_idf('金融', text4))
0.0
0.010449184321130576
0.0
0.0005604100558927716
可见,词语“金融”很能代表 财经类文本,可以作为财经类文本的关键词。
四、Ngrams的实现
nltk.util模块可以帮助我们快速实现Ngrams
4.1 bigrams/trigrams
from nltk.util import bigrams,trigrams
#bigrams返回的是生成器,需要list才能直接显示出来
print(list(bigrams([1,2,3,4,5])))
print(list(trigrams([1,2,3,4,5])))
[(1, 2), (2, 3), (3, 4), (4, 5)]
[(1, 2, 3), (2, 3, 4), (3, 4, 5)]
4.2 ngrams(sequence, n)
将序列生成n连词组序列
from nltk.util import ngrams
#生成3连词组序列
list(ngrams([1,2,3,4,5], 3))
[(1, 2, 3), (2, 3, 4), (3, 4, 5)]
4.3 skipgrams(sequence, n, k)
from nltk.util import skipgrams
sent = "a b c d e f".split()
print(list(skipgrams(sent, 2, 1)))
print(list(skipgrams(sent, 3, 1)))
[('a', 'b'), ('a', 'c'), ('b', 'c'), ('b', 'd'), ('c', 'd'), ('c', 'e'), ('d', 'e'), ('d', 'f'), ('e', 'f')]
[('a', 'b', 'c'), ('a', 'b', 'd'), ('a', 'c', 'd'), ('b', 'c', 'd'), ('b', 'c', 'e'), ('b', 'd', 'e'), ('c', 'd', 'e'), ('c', 'd', 'f'), ('c', 'e', 'f'), ('d', 'e', 'f')]
五、probability模块
probability模块中有两个比较好用的类,一个是FreqDist,另一个是ConditionFreqDist类。
FreqDist可以实现词频计算,并制图
ConditionFreqDist可以实现带条件的词频计算,并制图。
5.1 FreqDist类
5.1.1初始化词语列表为FreqDist对象
from nltk.probability import FreqDist
novel_data = open('texts/三体全集.txt').read()
cleaned_data = ''.join(re.findall(r'[\u4e00-\u9fa5]', novel_data))
wordlist = jieba.lcut(cleaned_data)
#创建包含给定样本的频率分布(传入词语列表)
fdist = FreqDist(wordlist)
5.1.2 打印词语列表
#打印词列表
print(fdist.keys())
dict_keys(['刘慈欣', '三体', '终于', '能', '与', '科幻', '朋友', '们', '见面', '了', '用', '连载', '的', '方式', '事先', '谁', '都', '没有', '想到', '也', '是', '无奈', '之', '举', '之前', '就', '题材', '问题', '编辑', '仔细', '商讨', '过', '感觉', '什么', '但', '没想到', '今年', '文革', '三十周年', '这', '事儿', '单行本', '一时', '出', '不了', '只能', '这样', '其实', '本书', '不是', '内容', '在', '其中', '只', '占', '不到', '十分之一', '却是', '一个', '漂荡', '故事', '中', '挥之不去', '精神', '幽灵',...... '虽', '球状', '闪电', '续集', '可以', '看做', '那个', '所', '发生', '世界', '其后', '延续', '物理学家', '出现', '已', '不', '重要', '其他', '人', '则', '永远', '消失', '林云', '真的', '死', '虽然', '我', '有时', '想', '如果', '她', '活', '下来', '最后', '是不是', '这个', '主人公', '样子', '这是', '暂', '名为', '地球', '往事', '系列', '第一部', '更长', '开始', '关于', '背叛', '生存', '死亡', '有时候', '比起', '还是', '忠诚', '可能', '更是', '疯狂', '偏执'])
5.1.3 打印词语与频数对
#打印词语与出现次数数据
print(fdist.items())
dict_items([('刘慈欣', 11), ('三体', 841), ('终于', 110), ('能', 897), ('与', 1349), ('科幻', 54), ('朋友', 24), ('们', 309), ('见面', 16), ('了', 10167), ('用', 644), ('连载', 3), ('的', 36268), ('方式', 103), ('事先', 2), ('谁', 234), ('都', 2951)........('没有', 2128), ('想到', 153), ('也', 2671), ('是', 7110), ('无奈', 7), ('之', 106), ('举', 12), ('之前', 138), ('就', 2233), ('题材', 3), ('问题', 318), ('编辑', 3), ('仔细', 41), ('商讨', 1), ('过', 695), ('感觉', 468), ('什么', 1177), ('但', 2670), ('没想到', 22), ('今年', 6), ('文革', 22), ('三十周年', 1), ('这', 2911), ('事儿', 85), ('单行本', 1), ('一时', 36), ('出', 359), ('不了', 58), ('只能', 325)】)
5.1.4 词语总数
#打印词语总数
print(fdist.N())
457899
5.1.5 打印出现次数最多的词语
print(fdist.max())
的
5.1.6 输出某个词的出现次数
print(fdist['三体'])
841
5.1.7 计算词频
#计算词频
print(fdist.freq('三体'))
0.0018366495668258721
5.1.8 绘制前20个词频数累计图
#总词数45万,前20个词占据了总量的近25%
fdist.plot(20,cumulative=True)
Tables | Are |
---|---|
fdist = FreqDist(wordlist) | 将wordlist化为FreqDist对象 |
fdist.inc(wordlist2) | 增加新数据 |
fdist['monstrous'] | 'monstrous'的频数 |
fdist.freq('monstrous') | 'monstrous'的频率 |
fdist.N() | wordlist中词语总数 |
fdist.keys() | wordlist中的词语列表 |
fdist.max() | wordlist中出现次数最多的词语 |
fdist.plot() | 绘制频数分布图 |
5.2 ConditionFreqDist类
带条件的频率分布类
条件和事件 频率分布计算观察到的事件,如文本中出现的词汇。条件频率分布需要事件关联一个条件,所以不是处理一个词序列,而是配对的序列。
text = ['The', 'Fulton', 'County', 'Grand', 'Jury', 'said', ...]
pairs = [('news', 'The'), ('news', 'Fulton'), ('news', 'County'), ...]
每对的形式:(条件,事件)。
from nltk.probability import ConditionalFreqDist
import re
import jieba
def text_split(file):
"""
对文本进行分词,返回分词后的列表
"""
novel_data = open(file).read()
cleaned_data = ''.join(re.findall(r'[\u4e00-\u9fa5]', novel_data))
wordlist = jieba.lcut(cleaned_data)
return wordlist
texts = ['体育.txt','财经.txt','新闻.txt','科技.txt']
cfd = ConditionalFreqDist(
(text,len(word))
for text in texts
for word in text_split(text))
#计算前10大词在各类文本中的频数
cfd.tabulate(conditions=['体育.txt','财经.txt','新闻.txt','科技.txt'],samples=range(10))
六、文本分类之朴素贝叶斯
这里使用nltk提供的数据 male.txt female.txt做为训练出一个模型,输入一个名字,预测一个人名的性别。
训练模型需要使用特征,这里我们假定使用名字最后一个字母作为特征。这里类比一下,比如中文中出现"亭"/"芳",很大的可能性是女名。而“国”、“帅”、"凯"极大的可能性是男名。
import randomfrom nltk import NaiveBayesClassifier
#读取名字数据
def gender_data(file):
names = []
for line in open(file).readlines():
name = line.strip()
names.append(name)
return names
#这里({name:True},'male')({name:True},'female'),nltk内部的NaiveBayesClassifier我还没研究,所以这里只能将就
males = [({name[-1]:True},'male')
for name in gender_data(file='names/male.txt')]
females = [({name[-1]:True},'female')
for name in gender_data(file='names/female.txt')]
names = (males+females)#打乱顺序random.shuffle(names)
#特征集
featuresets = [(name,gender) for (name,gender) in names]
#将特征集分为训练集和测试集
train_set, test_set = featuresets[500:],featuresets[:500]
#使用训练集训练分类器
classifier = NaiveBayesClassifier.train(train_set)
print(classifier.classify({'David'[-1]:True}))
print(classifier.classify({'Mike'[-1]:True}))
print(classifier.classify({'Lucy'[-1]:True}))
print(classifier.classify({'Adelina[-1]':True}))
#分类器准确性
print(nltk.classify.accuracy(classifier, test_set))
male
male
female
female
0.748
分类器的准确率达到0.748,还是挺不错的哦。
历史文章:
数据采集
【视频】有了selenium,小白也可以自豪的说:“去TMD的抓包、cookie”
【视频】快来get新技能--抓包+cookie,爬微博不再是梦
文本处理分析
图片数据处理
其他
项目下载
链接: https://pan.baidu.com/s/1slof6Df 密码: 2rq8